﻿using HDS.Common.Helper;
using HDS.Model.MongoDb;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace HDS.Data.MongoDB
{
    public class MongoDbContext
    {
        private readonly MongoClient mongoClient;
        private readonly IMongoDatabase mongoDatabase;

        public MongoDbContext(string configId, string databaseName)
        {
            mongoClient = new MongoClient(AppSettings.GetAppSettingValue(new string[] { "MongoDB", configId }));
            mongoDatabase = mongoClient.GetDatabase(databaseName);
        }

        public IMongoCollection<T> GetCollection<T>()
        {
            var collectionName = typeof(T).Name;
            return mongoDatabase.GetCollection<T>(collectionName);
        }

        public IMongoCollection<T> GetCollection<T>(string collectionName)
        {
            return mongoDatabase.GetCollection<T>(collectionName);
        }

        public async Task<T> GetFirstOrDefault<T, E>(E id) where T : BaseObject<E>
        {
            var CON = GetCollection<T>();
            var IC = await CON.FindAsync<T>(e => e.Id.Equals(id));
            return IC.FirstOrDefault();
        }

        public async Task<T> GetFirstOrDefault<T>(Expression<Func<T, bool>> filter)
        {
            var CON = GetCollection<T>();
            var IC = await CON.FindAsync<T>(filter);
            return IC.FirstOrDefault();
        }

        public async Task BulkWriteAsync<T, E>(IEnumerable<T> list) where T : BaseObject<E>
        {
            if (!list.Any())
                return;

            var models = new List<WriteModel<T>>();
            var CON = GetCollection<T>();
            foreach (var entity in list)
            {
                var model = new ReplaceOneModel<T>(Builders<T>.Filter.Eq<E>(p => p.Id, entity.Id), entity);
                model.IsUpsert = true;
                models.Add(model);
            }

            await CON.BulkWriteAsync(models, new BulkWriteOptions { IsOrdered = false, BypassDocumentValidation = true });
        }

        public async Task<IList<T>> GetListAysnc<T>(Expression<Func<T, bool>> filter)
        {
            var CON = GetCollection<T>();
            var IC = await CON.FindAsync<T>(filter);
            return await IC.ToListAsync();
        }
    }
}